package com.beiding.businessplatform.utils;

import com.example.demo.auto.entity.ABe;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

public class EntityUtils {


    private static class HolderType {
        //key
        private String key;

        private String parentKey;

        //实例类型
        private Class instanceType;
        //持有者类型
        private int holderType;

        //相对父节点的key
        private String keyFromParent;

    }

    private static class MappingHelp {

        private Map<Class, Map<Object, Object>> mappings = new HashMap<>();

        private Map<String, HolderType> holderTypeMap = new HashMap<>();

/*
        void newRootById(Class rootType, Object id, RowKeyData rowKeyData) {

            Map<Object, Object> oMap = mappings.computeIfAbsent(rootType, k -> new HashMap<>());
            Object o = oMap.getValue(id);
            if (o == null) {
                try {
                    o = rootType.newInstance();
                    oMap.put(id, o);

                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
            rowKeyData.holderType = 0;
            rowKeyData.obj = o;
            rowKeyData.key = "";
        }*/

        //根据id进行
        void newById(Class rootType, String key, Object id, RowKeyData rowKeyData) {

            HolderType holderType;
            if (holderTypeMap.containsKey(key)) {
                holderType = holderTypeMap.get(key);
                if (holderType == null) {
                    return;
                }
            } else {
                holderType = theKeyType(rootType, key);
                if (holderType == null) {
                    holderTypeMap.put(key, null);
                    return;
                }

                holderTypeMap.put(key, holderType);
            }


            try {

                //实例化对象
                Map<Object, Object> map = mappings.computeIfAbsent(holderType.instanceType, k -> new HashMap<>());
                Object o = map.get(id);
                if (o == null) {
                    o = holderType.instanceType.newInstance();
                    map.put(id, o);
                }
                rowKeyData.key = key;
                rowKeyData.obj = o;
                rowKeyData.keyFromParent = holderType.keyFromParent;
                rowKeyData.holderType = holderType.holderType;
                rowKeyData.parentKey = holderType.parentKey;
            } catch (Exception e) {
                throw new RuntimeException(e);
            }

        }
    }

    /*
        id,name,b_id,b_name
     */

    private static class RowKeyData {
        private String key;
        private String parentKey;

        private Map<String, Object> data = new HashMap<>();
        private Object obj;

        //当前节点相对于父节点的字段名称
        private String keyFromParent;

        /*
            0 :无持有
            1 :直接持有
            2 :列表容器持有
         */
        private int holderType;
    }


    /*

        首先根据id进行翻折,处理成Map

        然后根据Id链进行对象组装

        最后处理值部分,再一次遍历Map

        节点的存在必须id字段有值

        例如:B是A的子节点

        字段    ABe       B
        值     a1      b1
        值     a2      b2

        如上, a1对应b1,a2对应b2
        正常查询结果
          id    b_id
          a1    b1
          a2    b2

         如此可以得到两个根节点,id分别为 a1 和 a2 的A,而这两个根节点分别对应id为b1和b2的两个B节点

         但如果不提供id信息
         即:
            id      b_id
            null    b1
            null    b2

         那么,就无法确定id分别为b1和b2的两个B节点是否对应同一个A节点


     */
    public static <T> List<T> mappingData(List<Map<String, Object>> list, Class<T> clz, String idFieldName) {

        List<T> r = new ArrayList<>();

        MappingHelp mappingHelp = new MappingHelp();

        //第一次处理放入根据字段处理成数据树
        for (Map<String, ?> map : list) {

            if (!map.containsKey("id")) {
                continue;
            }

            //TODO 移除掉没有意义的空白节点
            Map<String, RowKeyData> os = new HashMap<>();

            map.forEach((k, v) -> {
                int i = k.lastIndexOf("_");
                if (i != -1) {
                    String preKey = k.substring(0, i);
                    String key = k.substring(i + 1);
                    RowKeyData holder = os.computeIfAbsent(preKey, theKey -> new RowKeyData());
                    if (key.equals(idFieldName)) {
                        if (v != null) {
                            mappingHelp.newById(clz, preKey, v, holder);
                        }
                    }
                    holder.data.put(key, v);

                } else {
                    RowKeyData holder = os.computeIfAbsent("", theKey -> new RowKeyData());
                    if (k.equals(idFieldName)) {
                        if (v != null) {
                            mappingHelp.newById(clz, "", v, holder);
                        }
                    }
                    holder.data.put(k, v);
                }

            });

            if (!os.containsKey("")) {
                continue;
            }

            //确保父节点存在
        /*    for (RowKeyData holder : new ArrayList<>(os.values())) {
                if (os.containsKey(holder.parentKey)) {
                    continue;
                }
                makeSureParentNode(clz, os, holder);
            }*/

            for (RowKeyData holder : os.values()) {

                Object obj = holder.obj;
                if (obj == null) {
                    continue;
                }
                Class<?> objClass = obj.getClass();

                //赋值操作
                holder.data.forEach((k, v) -> {

                    //TODO 进行对象赋值
                    try {
                        Field declaredField = objClass.getDeclaredField(k);
                        declaredField.setAccessible(true);
                        declaredField.set(obj, v);//赋值失败不做任何处理
                    } catch (NoSuchFieldException e) {
                        System.out.println(objClass + " 无字段 " + k);
                    } catch (IllegalAccessException | IllegalArgumentException e) {
                        System.out.println(objClass + " 赋值失败 字段:" + k + "   值:" + v);
                    }

                });

                //TODO 链式组装

                if (!holder.key.equals("")) {
                    RowKeyData rowKeyData = os.get(holder.parentKey);
                    if (rowKeyData != null) {
                        Object h = rowKeyData.obj;
                        if (holder.holderType == 1) {
                            try {
                                Field declaredField = h.getClass().getDeclaredField(holder.keyFromParent);
                                declaredField.setAccessible(true);
                                declaredField.set(h, holder.obj);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }
                        } else if (holder.holderType == 2) {
                            try {
                                Field declaredField = h.getClass().getDeclaredField(holder.keyFromParent);
                                declaredField.setAccessible(true);
                                List o = (List) declaredField.get(h);
                                if (o == null) {
                                    o = new ArrayList();
                                    declaredField.set(h, o);
                                }
                                o.add(holder.obj);
                            } catch (Exception e) {
                                throw new RuntimeException(e);
                            }

                        }
                    }
                }

            }

            RowKeyData rowKeyData = os.get("");

            if (rowKeyData != null) {
                T o = (T) rowKeyData.obj;
                if (!r.contains(o)) {
                    r.add(o);
                }
            }

        }

        return r;
    }

  /*  private static void makeSureParentNode(Class rootType, Map<String, RowKeyData> holderMap, RowKeyData holder) {

        RowKeyData p = holderMap.getValue(holder.parentKey);
        if (p == null) {

            HolderType holderType = theKeyType(rootType, holder.parentKey);

            if (holderType == null) {
                return;
            }

            p = new RowKeyData();
            p.key = holderType.key;
            p.keyFromParent = holderType.keyFromParent;
            p.holderType = holderType.holderType;
            p.parentKey = holderType.parentKey;
            try {
                p.obj = holderType.instanceType.newInstance();
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            //放入key
            holderMap.put(p.key, p);
            if (!holderMap.containsKey(p.parentKey)) {
                if (!p.parentKey.equals("")) {
                    makeSureParentNode(rootType, holderMap, p);
                }
            }
        }
    }*/


    private static HolderType theKeyType(Class rootType, String key) {
        HolderType holderType = new HolderType();

        //如果是根节点
        if (key.equals("")) {
            holderType.key = key;
            holderType.instanceType = rootType;
            holderType.holderType = 0;
            return holderType;
        }


        String[] split = key.split("_");
        Field field = null;

        Class type = rootType;
        for (String s : split) {
            try {
                field = type.getDeclaredField(s);
                fieldType(field, holderType);
                type = holderType.instanceType;
            } catch (Exception ignore) {
                break;
            }

        }

        if (field == null) {
            return null;
        }

        int i = key.lastIndexOf("_");

        if (i == -1) {
            holderType.keyFromParent = key;
            holderType.parentKey = "";
        } else {
            holderType.keyFromParent = key.substring(i + 1);
            holderType.parentKey = key.substring(0, i);
        }

        return holderType;
    }


    private static void fieldType(Field field, HolderType holderType) {
        Class<?> type = field.getType();
        if (List.class.isAssignableFrom(type)) {
            Type genericType = field.getGenericType();
            if (genericType instanceof ParameterizedType) {
                ParameterizedType t = (ParameterizedType) genericType;
                Type[] actualTypeArguments = t.getActualTypeArguments();
                if (actualTypeArguments.length == 1) {
                    holderType.instanceType = (Class) actualTypeArguments[0];
                    holderType.holderType = 2;//列表持有
                } else {
                    holderType.instanceType = Object.class;
                    holderType.holderType = 2;//列表持有
                }
            } else {
                holderType.instanceType = Object.class;
                holderType.holderType = 2;//列表持有
            }
        } else {
            holderType.instanceType = type;
            holderType.holderType = 1;//直接持有
        }
    }

    public static void main(String[] args) throws NoSuchFieldException {

      /*  Field bsB = ABe.class.getDeclaredField("bsB");

        System.out.println(theKeyType(bsB));
*/

        List<Map<String, Object>> list = new ArrayList<>();
        Map<String, Object> map = new HashMap<>();
        map.put("id", "123");
        map.put("name", "测试");
        map.put("bs_id", "456");
        map.put("bs_name", "aaaa");
        map.put("bs_kkk", "测试2");
        map.put("bs_a_id", "123");
        list.add(map);

        map = new HashMap<>();
        map.put("id", "123");
        map.put("name", "测试");
        map.put("bs_id", "789");
        map.put("bs_name", "测试2");
        map.put("bs_a_id", "123");

        list.add(map);


        List<ABe> as = mappingData(list, ABe.class, "id");

        for (ABe a : as) {
            System.out.println(a);
        }

    }


}
